package com.zzl.study.nacos.discovery;

import com.zzl.study.nacos.properties.NacosMultiDiscoveryProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.discovery.event.HeartbeatEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.SmartLifecycle;
import org.springframework.lang.NonNull;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

import java.time.Duration;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Nacos多注册中心服务发现心跳事件发布器
 *
 * @author: zhangzl
 * @date: 2025/7/16 15:33
 * @version: 1.0
 */
@Slf4j
public class NacosMultiDiscoveryHeartBeatPublisher implements ApplicationEventPublisherAware, SmartLifecycle {

    /**
     * Nacos多注册中心属性配置
     */
    private final NacosMultiDiscoveryProperties nacosMultiDiscoveryProperties;

    /**
     * 定时任务线程池
     */
    private final ThreadPoolTaskScheduler taskScheduler;

    /**
     * 心跳索引
     */
    private final AtomicLong nacosHeartBeatIndex = new AtomicLong(0);

    /**
     * 运行状态
     */
    private final AtomicBoolean running = new AtomicBoolean(false);

    /**
     * Spring事件发布器
     */
    private ApplicationEventPublisher publisher;

    /**
     * 心跳任务Future
     */
    private ScheduledFuture<?> heartBeatFuture;

    /**
     * 构造函数
     *
     * @param nacosMultiDiscoveryProperties Nacos多注册中心属性配置
     */
    public NacosMultiDiscoveryHeartBeatPublisher(NacosMultiDiscoveryProperties nacosMultiDiscoveryProperties) {
        this.nacosMultiDiscoveryProperties = nacosMultiDiscoveryProperties;
        this.taskScheduler = getTaskScheduler();
    }

    @Override
    public void start() {
        if (this.running.compareAndSet(false, true)) {
            log.info("Start nacos heartBeat task scheduler.");
            long watchDelay = this.nacosMultiDiscoveryProperties.getWatchDelay();
            this.heartBeatFuture = this.taskScheduler.scheduleWithFixedDelay(this::publishHeartBeat, Duration.ofMillis(watchDelay));
        }
    }

    @Override
    public void stop() {
        if (this.running.compareAndSet(true, false)) {
            if (this.heartBeatFuture != null) {
                this.taskScheduler.shutdown();
                this.heartBeatFuture.cancel(true);
            }
        }
    }

    @Override
    public boolean isRunning() {
        return this.running.get();
    }

    @Override
    public void setApplicationEventPublisher(@NonNull ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    /**
     * 发布服务发现心跳事件
     */
    private void publishHeartBeat() {
        HeartbeatEvent event = new HeartbeatEvent(this, nacosHeartBeatIndex.getAndIncrement());
        this.publisher.publishEvent(event);
    }

    /**
     * 构建定时任务线程池
     *
     * @return 定时任务线程池
     */
    private static ThreadPoolTaskScheduler getTaskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setBeanName("HeartBeat-Task-Scheduler");
        taskScheduler.initialize();
        return taskScheduler;
    }

}
